#include "vulkan/vulkan.hpp"
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <vector>
#include <vulkan/vk_platform.h>
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
#include <vulkan/vulkan_structs.hpp>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

constexpr uint32_t WIDTH = 800;
constexpr uint32_t HEIGHT = 600;

const std::vector<char const *> validationLayers = {
    "VK_LAYER_KHRONOS_validation"};

#ifdef NDEBUG
constexpr bool enableValidationLayers = false;
#else
constexpr bool enableValidationLayers = true;
#endif

class HelloTriangleApplication {
public:
  void run() {
    initWindow();
    initVulkan();
    mainLoop();
    cleanup();
  }

private:
  GLFWwindow *window = nullptr;

  vk::raii::Context context;
  vk::raii::Instance instance = nullptr;
  vk::raii::DebugUtilsMessengerEXT debugMessenger = nullptr;
  vk::raii::PhysicalDevice physicalDevice = nullptr;
  vk::raii::Device device = nullptr;
  vk::raii::Queue graphicsQueue = nullptr;
  uint32_t graphicsIndex = ~0;
  vk::raii::SurfaceKHR surface = nullptr;

  vk::raii::SwapchainKHR swapchain = nullptr;
  std::vector<vk::Image> swapchainImages;
  vk::SurfaceFormatKHR swapChainSurfaceFormat;
  vk::Extent2D swapchainExtent;
  std::vector<vk::raii::ImageView> swapchainImageViews;

  vk::raii::PipelineLayout pipelineLayout = nullptr;
  vk::raii::Pipeline graphicsPipeline = nullptr;

  vk::raii::CommandPool commandPool = nullptr;
  vk::raii::CommandBuffer commandBuffer = nullptr;

  vk::raii::Semaphore presentCompleteSemaphore = nullptr;
  vk::raii::Semaphore renderCompleteSemaphore = nullptr;
  vk::raii::Fence drawFence = nullptr;

  std::vector<const char *> requiredDeviceExtension = {
      // 交换链扩展
      vk::KHRSwapchainExtensionName,
      // SPIR-V 1.4 扩展
      vk::KHRSpirv14ExtensionName,
      // 同步2扩展
      vk::KHRSynchronization2ExtensionName,
      // 创建渲染通道2扩展
      vk::KHRCreateRenderpass2ExtensionName,
#if defined(__APPLE__) || defined(__MOLENGVK__)
      // Portability Subset 扩展，macOS/MoltenVK 必需
      "VK_KHR_portability_subset"
#endif
  };

  void initWindow() {
    glfwInit();

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
  }

  void initVulkan() {
    createInstance();
    // 注释掉setupDebugMessenger()调用，因为调试信使已经在实例创建时通过pNext链激活
    // setupDebugMessenger();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
    createSwapChain();
    createImageViews();
    createGraphicsPipeline();
    createCommandPool();
    createCommandBuffers();
    createSyncObjects();
  }

  void mainLoop() {
    while (!glfwWindowShouldClose(window)) {
      glfwPollEvents();
      drawFrame();
    }
    device.waitIdle();
  }

  void cleanup() {
    glfwDestroyWindow(window);
    glfwTerminate();
  }

  void createInstance() {
    constexpr vk::ApplicationInfo appInfo(
        "Hello Triangle", VK_MAKE_VERSION(1, 0, 0), "No Engine",
        VK_MAKE_VERSION(1, 0, 0), vk::ApiVersion14);

    // Get the required layers
    std::vector<char const *> requiredLayers;
    if (enableValidationLayers) {
      requiredLayers.assign(validationLayers.begin(), validationLayers.end());
    }

    // Check if the required layers are supported by the Vulkan implementation.
    auto layerProperties = context.enumerateInstanceLayerProperties();
    for (auto const &requiredLayer : requiredLayers) {
      // 打印验证的layer
      std::cout << "Checking layer: " << requiredLayer << std::endl;
      // 使用 C++20 的 std::ranges::none_of 算法
      // 检查 layerProperties 容器中是否没有任何元素满足 lambda 表达式的条件
      // lambda 表达式比较层属性中的 layerName 与 requiredLayer 是否相等
      // 使用 strcmp 进行字符串比较
      if (std::ranges::none_of(
              layerProperties, [requiredLayer](auto const &layerProperty) {
                return strcmp(layerProperty.layerName, requiredLayer) == 0;
              })) {
        throw std::runtime_error("Required layer not supported: " +
                                 std::string(requiredLayer));
      }
    }

    // Get the required extensions.
    auto requiredExtensions = getRequiredExtensions();
#ifdef __APPLE__
    requiredExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
    // Check if the required extensions are supported by the Vulkan
    // implementation.
    auto extensionProperties = context.enumerateInstanceExtensionProperties();

    for (auto const &requiredExtension : requiredExtensions) {
      // 打印验证的extension
      std::cout << "Checking extension: " << requiredExtension << std::endl;
      if (std::ranges::none_of(
              extensionProperties,
              [requiredExtension](auto const &extensionProperty) {
                return strcmp(extensionProperty.extensionName,
                              requiredExtension) == 0;
              })) {
        throw std::runtime_error("Required extension not supported: " +
                                 std::string(requiredExtension));
      }
    }

    // 配置调试信使创建信息，在实例创建时就激活调试回调
    vk::DebugUtilsMessengerCreateInfoEXT debugCreateInfo;
    if (enableValidationLayers) {
      // 指定要捕获的消息严重级别：Verbose（详细信息）、Warning（警告）、Error（错误）
      vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(
          vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
          vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
          vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);

      // 指定要捕获的消息类型：General（通用）、Performance（性能）、Validation（验证）
      vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(
          vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
          vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
          vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);

      // 创建调试信使的创建信息结构体
      debugCreateInfo = vk::DebugUtilsMessengerCreateInfoEXT{
          {}, severityFlags, messageTypeFlags, &debugCallback};
    }

    vk::InstanceCreateInfo createInfo(
#ifdef __APPLE__
        static_cast<vk::InstanceCreateFlags>(
            VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR),
#else
        {},
#endif
        &appInfo, static_cast<uint32_t>(requiredLayers.size()),
        requiredLayers.data(), static_cast<uint32_t>(requiredExtensions.size()),
        requiredExtensions.data());

    // 如果启用了验证层，将调试信使创建信息链接到实例创建信息的pNext链中
    if (enableValidationLayers) {
      createInfo.setPNext(&debugCreateInfo);
    }

    instance = vk::raii::Instance(context, createInfo);
  }
  // 设置调试信使：用于捕获并打印 Vulkan 验证层的调试信息
  void setupDebugMessenger() {
    // 如果未启用验证层，直接返回，无需创建调试信使
    if (!enableValidationLayers)
      return;

    // 指定要捕获的消息严重级别：Verbose（详细信息）、Warning（警告）、Error（错误）
    vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(
        vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
        vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
        vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);

    // 指定要捕获的消息类型：General（通用）、Performance（性能）、Validation（验证）
    vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(
        vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
        vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
        vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);

    // 创建调试信使的创建信息结构体
    // 第一个参数 {} 是默认的 vk::StructureChain
    // 空初始化，其余依次填入严重级别、消息类型、回调函数指针
    vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfoEXT{
        {}, severityFlags, messageTypeFlags, &debugCallback};

    // 利用已创建的 Vulkan 实例创建调试信使对象，并赋值给成员变量 debugMessenger
    debugMessenger =
        instance.createDebugUtilsMessengerEXT(debugUtilsMessengerCreateInfoEXT);
  }

  void pickPhysicalDevice() {
    // 枚举物理设备
    auto devices = instance.enumeratePhysicalDevices();
    const auto devIter = std::ranges::find_if(devices, [&](auto const &device) {
      // 检查物理设备是否支持Vulkan 1.3 API版本
      bool supportsVulkan1_3 =
          device.getProperties().apiVersion >= VK_API_VERSION_1_3;

      // 检查物理设备是否支持图形操作的队列家族
      auto queueFamilies = device.getQueueFamilyProperties();
      bool supportsGraphics =
          std::ranges::any_of(queueFamilies, [](auto const &qfp) {
            return !!(qfp.queueFlags & vk::QueueFlagBits::eGraphics);
          });

      // 检查物理设备是否支持所有需要的设备扩展
      auto availableDeviceExtensions =
          device.enumerateDeviceExtensionProperties();
      bool supportsAllRequiredExtensions = std::ranges::all_of(
          requiredDeviceExtension,
          [&availableDeviceExtensions](auto const &requiredDeviceExtension) {
            return std::ranges::any_of(
                availableDeviceExtensions,
                [requiredDeviceExtension](
                    auto const &availableDeviceExtension) {
                  return strcmp(availableDeviceExtension.extensionName,
                                requiredDeviceExtension) == 0;
                });
          });

      auto features = device.template getFeatures2<
          vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan11Features,
          vk::PhysicalDeviceVulkan13Features,
          vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
      bool supportsRequiredFeatures =
          features.template get<vk::PhysicalDeviceVulkan11Features>()
              .shaderDrawParameters &&
          features.template get<vk::PhysicalDeviceVulkan13Features>()
              .synchronization2 &&
          features.template get<vk::PhysicalDeviceVulkan13Features>()
              .dynamicRendering &&
          features.template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>()
              .extendedDynamicState;

      return supportsVulkan1_3 && supportsGraphics &&
             supportsAllRequiredExtensions && supportsRequiredFeatures;
    });
    if (devIter != devices.end()) {
      physicalDevice = *devIter;
    } else {
      throw std::runtime_error("failed to find a suitable GPU!");
    }
  }
  // 调试回调函数：被 Vulkan 验证层调用，用于输出调试信息
  // VKAPI_ATTR 和 VKAPI_CALL 确保使用 Vulkan 所需的调用约定
  static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback(
      vk::DebugUtilsMessageSeverityFlagBitsEXT severity, // 消息严重级别
      vk::DebugUtilsMessageTypeFlagsEXT type,            // 消息类型
      const vk::DebugUtilsMessengerCallbackDataEXT
          *pCallbackData, // 包含详细消息内容的回调数据
      void *              // 用户自定义数据指针（此处未使用）
  ) {
    // 仅当消息为错误或警告时才打印，避免冗余输出
    // if (severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eError ||
    //    severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning)
    //{
    // 输出消息类型与具体信息到标准错误流
    std::cerr << "validation layer: type " << to_string(type)
              << " msg: " << pCallbackData->pMessage << std::endl;
    //}

    // 返回 vk::False 表示该消息未被应用层“处理”，Vulkan 将继续传递该消息
    return vk::False;
  }
  std::vector<const char *> getRequiredExtensions() {
    uint32_t glfwExtensionCount = 0;
    auto glfwExtensions =
        glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

    std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
    if (enableValidationLayers) {
      extensions.push_back(vk::EXTDebugUtilsExtensionName);
    }

    return extensions;
  }

  void createLogicalDevice() {
    // 获取物理设备支持的队列家族属性
    std::vector<vk::QueueFamilyProperties> queueFamilyProperties =
        physicalDevice.getQueueFamilyProperties();

    // get the first index into queueFamilyProperties which supports both
    // graphics and present
    for (uint32_t qfpIndex = 0; qfpIndex < queueFamilyProperties.size();
         qfpIndex++) {
      if ((queueFamilyProperties[qfpIndex].queueFlags &
           vk::QueueFlagBits::eGraphics) &&
          physicalDevice.getSurfaceSupportKHR(qfpIndex, *surface)) {
        // found a queue family that supports both graphics and present
        graphicsIndex = qfpIndex;
        break;
      }
    }
    if (graphicsIndex == ~0) {
      throw std::runtime_error(
          "Could not find a queue for graphics and present -> terminating");
    }

    // query for Vulkan 1.3 features
    vk::PhysicalDeviceFeatures2 feature2;
    vk::PhysicalDeviceVulkan13Features feature13;
    feature13.dynamicRendering = true;
    // 启用 shaderDrawParameters 特性以支持 gl_VertexIndex (SV_VERTEXID)
    vk::PhysicalDeviceShaderDrawParametersFeatures shaderDrawParamsFeatures;
    shaderDrawParamsFeatures.shaderDrawParameters = VK_TRUE;
    vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT featureEXT;
    featureEXT.extendedDynamicState = true;
    vk::StructureChain<vk::PhysicalDeviceFeatures2,
                       vk::PhysicalDeviceVulkan13Features,
                       vk::PhysicalDeviceShaderDrawParametersFeatures,
                       vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>
        featureChain = {feature2, feature13, shaderDrawParamsFeatures,
                        featureEXT};

    // create a Device
    float queuePriority = 0.0f;
    vk::DeviceQueueCreateInfo deviceQueueCreateInfo{
        {}, graphicsIndex, 1, &queuePriority};
    vk::DeviceCreateInfo deviceCreateInfo{};
    deviceCreateInfo.pNext = &featureChain.get<vk::PhysicalDeviceFeatures2>();
    deviceCreateInfo.queueCreateInfoCount = 1;
    deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
    deviceCreateInfo.enabledExtensionCount =
        static_cast<uint32_t>(requiredDeviceExtension.size());
    deviceCreateInfo.ppEnabledExtensionNames = requiredDeviceExtension.data();

    device = vk::raii::Device(physicalDevice, deviceCreateInfo);
    graphicsQueue = vk::raii::Queue(device, graphicsIndex, 0);
  }

  void createSurface() {
    VkSurfaceKHR _surface;
    if (glfwCreateWindowSurface(*instance, window, nullptr, &_surface) !=
        VK_SUCCESS) {
      throw std::runtime_error("Failed to create window surface!");
    }
    surface = vk::raii::SurfaceKHR(instance, _surface);
  }

  void createSwapChain() {
    // 查询交换链支持
    vk::SurfaceCapabilitiesKHR surfaceCapabilities =
        physicalDevice.getSurfaceCapabilitiesKHR(*surface);
    // 选择交换链图像扩展
    swapchainExtent = chooseSwapExtent(surfaceCapabilities);
    // 查询交换链格式支持
    std::vector<vk::SurfaceFormatKHR> availableSurfaceFormats =
        physicalDevice.getSurfaceFormatsKHR(*surface);
    // 选择交换链图像格式
    swapChainSurfaceFormat = chooseSwapSurfaceFormat(availableSurfaceFormats);

    // 创建交换链
    vk::SwapchainCreateInfoKHR swapchainCreateInfo{};
    // 选择交换链图像格式
    swapchainCreateInfo.surface = *surface;
    // 选择交换链图像数量
    swapchainCreateInfo.minImageCount =
        chooseSwapMinImageCount(surfaceCapabilities);
    swapchainCreateInfo.imageFormat = swapChainSurfaceFormat.format;
    swapchainCreateInfo.imageColorSpace = swapChainSurfaceFormat.colorSpace;
    swapchainCreateInfo.imageExtent = swapchainExtent;
    swapchainCreateInfo.imageArrayLayers = 1;
    swapchainCreateInfo.imageUsage = vk::ImageUsageFlagBits::eColorAttachment;
    swapchainCreateInfo.imageSharingMode = vk::SharingMode::eExclusive;
    swapchainCreateInfo.preTransform = surfaceCapabilities.currentTransform;
    swapchainCreateInfo.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
    // 查询交换链图像支持
    std::vector<vk::PresentModeKHR> availablePresentModes =
        physicalDevice.getSurfacePresentModesKHR(*surface);
    swapchainCreateInfo.presentMode =
        chooseSwapPresentMode(availablePresentModes);
    swapchainCreateInfo.clipped = true;

    swapchain = vk::raii::SwapchainKHR(device, swapchainCreateInfo);
    // 获取交换链图像
    swapchainImages = swapchain.getImages();
  }

  static uint32_t chooseSwapMinImageCount(
      vk::SurfaceCapabilitiesKHR const &surfaceCapabilities) {
    auto minImageCount = std::max(3u, surfaceCapabilities.minImageCount);
    if (surfaceCapabilities.maxImageCount > 0 &&
        minImageCount > surfaceCapabilities.maxImageCount) {
      minImageCount = surfaceCapabilities.maxImageCount;
    }
    return minImageCount;
  }

  vk::SurfaceFormatKHR chooseSwapSurfaceFormat(
      const std::vector<vk::SurfaceFormatKHR> &availableSurfaceFormats) {
    assert(!availableSurfaceFormats.empty());
    const auto formatIt = std::find_if(
        availableSurfaceFormats.begin(), availableSurfaceFormats.end(),
        [](const vk::SurfaceFormatKHR &format) {
          return format.format == vk::Format::eB8G8R8A8Srgb &&
                 format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear;
        });
    return formatIt != availableSurfaceFormats.end()
               ? *formatIt
               : availableSurfaceFormats[0];
  }
  vk::PresentModeKHR chooseSwapPresentMode(
      const std::vector<vk::PresentModeKHR> &availablePresentModes) {
    // 优先选择 Mailbox 模式，支持垂直同步
    assert(std::ranges::any_of(availablePresentModes,
                               [](const vk::PresentModeKHR &mode) {
                                 return mode == vk::PresentModeKHR::eFifo;
                               }));
    return std::ranges::any_of(availablePresentModes,
                               [](const vk::PresentModeKHR &mode) {
                                 return mode == vk::PresentModeKHR::eMailbox;
                               })
               ? vk::PresentModeKHR::eMailbox
               : vk::PresentModeKHR::eFifo;
  }

  vk::Extent2D
  chooseSwapExtent(const vk::SurfaceCapabilitiesKHR &surfaceCapabilities) {
    if (surfaceCapabilities.currentExtent.width !=
        std::numeric_limits<uint32_t>::max()) {
      return surfaceCapabilities.currentExtent;
    }
    // 否则，使用最小/最大图像扩展作为交换链图像扩展
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    return {
        std::clamp<uint32_t>(width, surfaceCapabilities.minImageExtent.width,
                             surfaceCapabilities.maxImageExtent.width),
        std::clamp<uint32_t>(height, surfaceCapabilities.minImageExtent.height,
                             surfaceCapabilities.maxImageExtent.height)};
  }
  void createImageViews() {
    assert(!swapchainImages.empty());

    vk::ImageViewCreateInfo imageViewCreateInfo{};
    imageViewCreateInfo.viewType = vk::ImageViewType::e2D;
    imageViewCreateInfo.format = swapChainSurfaceFormat.format;
    imageViewCreateInfo.subresourceRange =
        vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1);
    for (auto image : swapchainImages) {
      imageViewCreateInfo.image = image;
      swapchainImageViews.emplace_back(device, imageViewCreateInfo);
    }
  }
  static std::vector<char> readFile(const std::string &filename) {
    std::ifstream file(filename, std::ios::ate | std::ios::binary);
    if (!file.is_open()) {
      throw std::runtime_error("failed to open file!");
    }
    std::vector<char> buffer(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
    file.close();
    return buffer;
  }

  void createGraphicsPipeline() {
    vk::raii::ShaderModule shaderModule =
        createShaderModule(readFile("shaders/slang.spv"));
    // 顶点着色器
    vk::PipelineShaderStageCreateInfo vertShaderStageInfo{
        {}, vk::ShaderStageFlagBits::eVertex, shaderModule, "vertMain"};
    // 片段着色器
    vk::PipelineShaderStageCreateInfo fragShaderStageInfo{
        {}, vk::ShaderStageFlagBits::eFragment, shaderModule, "fragMain"};
    vk::PipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo,
                                                        fragShaderStageInfo};
    // 顶点输入状态,描述了传递给顶点着色器的顶点数据格式
    vk::PipelineVertexInputStateCreateInfo vertexInputInfo;
    // 输入装配状态,描述了输入顶点数据的拓扑结构,eTriangleList指每个三个顶点组成一个三角形
    vk::PipelineInputAssemblyStateCreateInfo inputAssembly{
        {}, vk::PrimitiveTopology::eTriangleList};
    // 视口状态,描述了渲染目标的视口和裁剪矩形
    vk::PipelineViewportStateCreateInfo viewportState{};
    // 描述了渲染目标的视口和裁剪矩形
    viewportState.viewportCount = 1;
    viewportState.scissorCount = 1;
    // 光栅化状态,描述了渲染三角形的方式,光栅化器将顶点几何转换为片段，执行深度测试、面剔除和裁剪测试
    vk::PipelineRasterizationStateCreateInfo rasterizer{
        {},
        vk::False,
        vk::False,
        vk::PolygonMode::eFill,
        vk::CullModeFlagBits::eBack,
        vk::FrontFace::eClockwise,
        vk::False,
        0.0f,
        0.0f,
        1.0f,
        1.0f};
    // 多采样状态,描述了渲染三角形的方式,多采样器将每个像素的颜色样本合并为一个最终颜色
    vk::PipelineMultisampleStateCreateInfo multisampling{
        {}, vk::SampleCountFlagBits::e1, vk::False};
    // 颜色混合状态,描述了渲染目标的颜色混合方式,颜色混合器将每个像素的颜色样本合并为一个最终颜色
    vk::PipelineColorBlendAttachmentState colorBlendAttachment{};
    // 当blendEnable设为VK_FALSE时直接采用片段着色器的新颜色。启用混合时进行颜色通道和alpha通道计算，最终结果与colorWriteMask进行AND运算。
    colorBlendAttachment.blendEnable = vk::False;
    colorBlendAttachment.colorWriteMask =
        vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
        vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
    // 启用位运算混合时设置logicOpEnable为VK_TRUE，logicOp字段指定位操作，此时会禁用常规混合方式。禁用两种模式时直接写入原始颜色。
    vk::PipelineColorBlendStateCreateInfo colorBlending{
        {}, vk::False, vk::LogicOp::eCopy, 1, &colorBlendAttachment};
    std::vector dynamicStates = {vk::DynamicState::eViewport,
                                 vk::DynamicState::eScissor};
    vk::PipelineDynamicStateCreateInfo dynamicState{
        {}, static_cast<uint32_t>(dynamicStates.size()), dynamicStates.data()};

    vk::PipelineLayoutCreateInfo pipelineLayoutInfo;

    pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo);

    vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo{};
    graphicsPipelineCreateInfo.stageCount = 2;
    graphicsPipelineCreateInfo.pStages = shaderStages;
    graphicsPipelineCreateInfo.pVertexInputState = &vertexInputInfo;
    graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssembly;
    graphicsPipelineCreateInfo.pViewportState = &viewportState;
    graphicsPipelineCreateInfo.pRasterizationState = &rasterizer;
    graphicsPipelineCreateInfo.pMultisampleState = &multisampling;
    graphicsPipelineCreateInfo.pColorBlendState = &colorBlending;
    graphicsPipelineCreateInfo.pDynamicState = &dynamicState;
    graphicsPipelineCreateInfo.layout = pipelineLayout;
    graphicsPipelineCreateInfo.renderPass = nullptr;

    vk::PipelineRenderingCreateInfo pipelineRenderingInfo{};
    pipelineRenderingInfo.colorAttachmentCount = 1;
    pipelineRenderingInfo.pColorAttachmentFormats =
        &swapChainSurfaceFormat.format;
    vk::StructureChain<vk::GraphicsPipelineCreateInfo,
                       vk::PipelineRenderingCreateInfo>
        pipelineCreateInfoChain = {graphicsPipelineCreateInfo,
                                   pipelineRenderingInfo};

    graphicsPipeline = vk::raii::Pipeline(
        device, nullptr,
        pipelineCreateInfoChain.get<vk::GraphicsPipelineCreateInfo>());
  }
  [[nodiscard]] vk::raii::ShaderModule
  createShaderModule(const std::vector<char> &code) const {
    vk::ShaderModuleCreateInfo createInfo{};
    createInfo.codeSize = code.size() * sizeof(char);
    createInfo.pCode = reinterpret_cast<const uint32_t *>(code.data());
    vk::raii::ShaderModule shaderModule{device, createInfo};

    return shaderModule;
  }
  void createCommandPool() {
    vk::CommandPoolCreateInfo poolInfo{};
    poolInfo.queueFamilyIndex = graphicsIndex;
    poolInfo.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
    commandPool = vk::raii::CommandPool(device, poolInfo);
  }
  void createCommandBuffers() {
    vk::CommandBufferAllocateInfo allocInfo{};
    allocInfo.commandPool = commandPool;
    allocInfo.level = vk::CommandBufferLevel::ePrimary;
    allocInfo.commandBufferCount = 1;
    commandBuffer =
        std::move(vk::raii::CommandBuffers(device, allocInfo).front());
  }

  void transition_image_layout(uint32_t currentFrame, vk::ImageLayout oldLayout,
                               vk::ImageLayout newLayout,
                               vk::AccessFlags2 src_access_mask,
                               vk::AccessFlags2 dst_access_mask,
                               vk::PipelineStageFlags2 src_stage_mask,
                               vk::PipelineStageFlags2 dst_stage_mask) {
    vk::ImageMemoryBarrier2 barrier{};
    barrier.srcStageMask = src_stage_mask;
    barrier.dstStageMask = dst_stage_mask;
    barrier.srcAccessMask = src_access_mask;
    barrier.dstAccessMask = dst_access_mask;
    barrier.oldLayout = oldLayout;
    barrier.newLayout = newLayout;
    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    barrier.image = swapchainImages[currentFrame];
    barrier.subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
    vk::DependencyInfoKHR dependencyInfo{};
    dependencyInfo.imageMemoryBarrierCount = 1;
    dependencyInfo.pImageMemoryBarriers = &barrier;
    commandBuffer.pipelineBarrier2(dependencyInfo);
  }

  void recordCommandBuffer(uint32_t imageIndex) {
    commandBuffer.begin({});
    // 在开始渲染之前,转换swapchain image to COLOR_AATATTACHMENT_OPTIMAL
    transition_image_layout(imageIndex, vk::ImageLayout::eUndefined,
                            vk::ImageLayout::eColorAttachmentOptimal, {},
                            vk::AccessFlagBits2::eColorAttachmentWrite,
                            vk::PipelineStageFlagBits2::eTopOfPipe,
                            vk::PipelineStageFlagBits2::eColorAttachmentOutput);
    vk::ClearValue clearColor = {{0.0f, 0.0f, 0.0f, 1.0f}};
    vk::RenderingAttachmentInfo attachmentInfo{};
    attachmentInfo.imageView = swapchainImageViews[imageIndex];
    attachmentInfo.imageLayout = vk::ImageLayout::eColorAttachmentOptimal;
    attachmentInfo.loadOp = vk::AttachmentLoadOp::eClear;
    attachmentInfo.storeOp = vk::AttachmentStoreOp::eStore;
    attachmentInfo.clearValue = clearColor;

    vk::Offset2D renderOffset(0, 0);
    vk::Rect2D renderArea(renderOffset, swapchainExtent);
    vk::RenderingInfo renderingInfo({},              // flags
                                    renderArea,      // renderArea
                                    1,               // layerCount
                                    0,               // viewMask
                                    1,               // colorAttachmentCount
                                    &attachmentInfo, // pColorAttachments
                                    nullptr,         // pDepthAttachment
                                    nullptr          // pStencilAttachment
    );

    commandBuffer.beginRendering(renderingInfo);
    commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics,
                               graphicsPipeline);
                               commandBuffer.setViewport(
        0,
        vk::Viewport(0.0f, 0.0f, static_cast<float>(swapchainExtent.width),
                     static_cast<float>(swapchainExtent.height), 0.0f, 1.0f));
    commandBuffer.setScissor(0,
                             vk::Rect2D(vk::Offset2D(0, 0), swapchainExtent));
    commandBuffer.draw(3, 1, 0, 0);
    commandBuffer.endRendering();

    // 在结束渲染之后,转换swapchain image to PRESENT_SRC_KHR
    transition_image_layout(imageIndex,
                            vk::ImageLayout::eColorAttachmentOptimal,
                            vk::ImageLayout::ePresentSrcKHR,
                            vk::AccessFlagBits2::eColorAttachmentWrite, {},
                            vk::PipelineStageFlagBits2::eColorAttachmentOutput,
                            vk::PipelineStageFlagBits2::eBottomOfPipe);
    commandBuffer.end();
  }

  void drawFrame() {
    graphicsQueue.waitIdle();
    auto [result, imageIndex] = swapchain.acquireNextImage(
        UINT64_MAX, *presentCompleteSemaphore, nullptr);
    recordCommandBuffer(imageIndex);

    device.resetFences(*drawFence);
    vk::PipelineStageFlags waitDestinationStageMask(
        vk::PipelineStageFlagBits::eColorAttachmentOutput);
    vk::SubmitInfo submitInfo{};
    submitInfo.waitSemaphoreCount = 1;
    submitInfo.pWaitSemaphores = &*presentCompleteSemaphore;
    submitInfo.pWaitDstStageMask = &waitDestinationStageMask;
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &*commandBuffer;
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = &*renderCompleteSemaphore;
    graphicsQueue.submit(submitInfo, *drawFence);

    while (vk::Result::eTimeout ==
           device.waitForFences(*drawFence, true, UINT64_MAX))
      ;

    vk::PresentInfoKHR presentInfo{};
    presentInfo.waitSemaphoreCount = 1;
    presentInfo.pWaitSemaphores = &*renderCompleteSemaphore;
    presentInfo.swapchainCount = 1;
    vk::SwapchainKHR swapchainHandle = *swapchain;
    presentInfo.pSwapchains = &swapchainHandle;
    presentInfo.pImageIndices = &imageIndex;
    result = graphicsQueue.presentKHR(presentInfo);

    switch (result) {
    case vk::Result::eSuccess:
      break;
    case vk::Result::eSuboptimalKHR:
      std::cout
          << "vk::Queue::presentKHR returned vk::Result::eSuboptimalKHR !\n"
          << std::endl;
      break;
    default:
      break;
    }
  }

  void createSyncObjects() {
    presentCompleteSemaphore =
        vk::raii::Semaphore(device, vk::SemaphoreCreateInfo());
    renderCompleteSemaphore =
        vk::raii::Semaphore(device, vk::SemaphoreCreateInfo());
    drawFence = vk::raii::Fence(
        device, vk::FenceCreateInfo(vk::FenceCreateFlagBits::eSignaled));
  }
};
int main() {
  try {
    HelloTriangleApplication app;
    app.run();
  } catch (const std::exception &e) {
    std::cerr << e.what() << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}